package xj.graph2d.app.prop;

import java.awt.Color;
import java.util.Comparator;

import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;

import xj.graph2d.app.resources.Style;
import xj.graph2d.table.FeatureTable;
import xj.graph2d.table.FeatureTableEntry;
import xj.model.uml.BasicModelElement;
import xj.model.uml.Operation;
import xj.model.uml.Visibility;

public class UMLOperationEntry implements FeatureTableEntry {

  // position of each column
  public static final int NAME_COLUMN = 0;

  public static final int TYPE_COLUMN = 1;

  public static final int PARAMETERS_COLUMN = 2;

  public static final int VISIBILITY_COLUMN = 3;

  public static final int CONCURRENCY_COLUMN = 4;

  public static final int ABSTRACT_COLUMN = 5;

  public static final int QUERY_COLUMN = 6;

  public static final int STATIC_COLUMN = 7;

  public static final int DELETE_COLUMN = 8;

  public static final String[] columnNames = { 
    "Name", 
    "Return Type",
    "Parameters", 
    "Visibility", 
    "Concurrency", 
    "Abstract", 
    "Query", 
    "Static",
    "Delete",
  };

  public static final String[] columnTips = { 
    "Name of the operation",
    "Return type of the operation", 
    "Parameters of the operation",
    "Visibility of the operation", 
    "Concurrency of the operation",
    "Is the operation abstract?", 
    "Is the operation a query?",
    "Is the operation static?", 
    "Delete the marked operation",
  };

  public static final Comparator[] comparators = {
      new FeatureEntryComparator(NAME_COLUMN),
      new FeatureEntryComparator(TYPE_COLUMN),
      new FeatureEntryComparator(PARAMETERS_COLUMN),
      new FeatureEntryComparator(VISIBILITY_COLUMN),
      new FeatureEntryComparator(CONCURRENCY_COLUMN),
      new FeatureEntryComparator(ABSTRACT_COLUMN),
      new FeatureEntryComparator(QUERY_COLUMN),
      new FeatureEntryComparator(STATIC_COLUMN), null, };

  public static TableCellEditor[] editors = new TableCellEditor[6];
  static {
    JComboBox type = new JComboBox();
    type.addItem("");
    type.addItem("void");
    type.addItem("boolean");
    type.addItem("int");
    type.addItem("char");
    type.addItem("byte");
    type.addItem("long");
    type.addItem("short");
    type.addItem("double");
    type.addItem("float");
    type.addItem("Collection");
    type.addItem("List");
    type.addItem("Set");
    type.addItem("Map");
    type.addItem("Object");
    type.addItem("String");
    type.addItem("Date");
    type.addItem("Time");
    type.setEditable(true);
    type.setBackground(Color.white);
    type.setFont(Style.editorFont);
    editors[TYPE_COLUMN] = new DefaultCellEditor(type);

    JComboBox visibility = new JComboBox();
    visibility.addItem("");
    visibility.addItem("public");
    visibility.addItem("protected");
    visibility.addItem("private");
    visibility.addItem("package");
    visibility.setBackground(Color.white);
    visibility.setFont(Style.editorFont);
    editors[VISIBILITY_COLUMN] = new DefaultCellEditor(visibility);

    JComboBox concurrency = new JComboBox();
    concurrency.addItem("");
    concurrency.addItem(Operation.Concurrency.Sequential);
    concurrency.addItem(Operation.Concurrency.Concurrent);
    concurrency.addItem(Operation.Concurrency.Guarded);
    concurrency.setBackground(Color.white);
    concurrency.setFont(Style.editorFont);
    editors[CONCURRENCY_COLUMN] = new DefaultCellEditor(concurrency);
  }

  public static TableCellRenderer[] renderers = { 
    null, null, null, null, null, null, null, null, 
    new FeatureTable.GrayBooleanRenderer(), // for Delete
  };

  public static final int[] columnWidths = { 50, 60, 150, 50, 60, 40, 40, 20, 20, };

  public UMLOperationEntry(Operation operation) {
    this.operation = operation;
  }

  public int getColumnCount() {
    return columnNames.length;
  }

  public String getColumnName(int col) {
    if (col >= 0 && col < columnNames.length) {
      return columnNames[col];
    }
    return null;
  }

  public Object getColumnValue(int col) {
    if (operation != null && col >= 0 && col < columnNames.length) {
      switch (col) {
      case NAME_COLUMN:
	return operation.getName();
      case TYPE_COLUMN:
	return operation.getType();
      case PARAMETERS_COLUMN:
	return operation.getParametersString();
      case VISIBILITY_COLUMN:
	return operation.getVisibility().toDisplayString();
      case CONCURRENCY_COLUMN:
	return operation.getConcurrency();
      case ABSTRACT_COLUMN:
	return operation.isAbstract();
      case QUERY_COLUMN:
	return operation.isQuery();
      case STATIC_COLUMN:
	return operation.isStatic();
      case DELETE_COLUMN:
	return deleted;
      }
    }
    return null;
  }

  public void setColumnValue(int col, Object value) {
    if (operation != null && col >= 0 && col < columnNames.length) {
      switch (col) {
      case NAME_COLUMN:
	if (value != null) {
	  operation.setName(value.toString());
	} else {
	  operation.setName(null);
	}
	break;
      case TYPE_COLUMN:
	if (value != null) {
	  operation.setType(value.toString());
	} else {
	  operation.setType(null);
	}
	break;
      case PARAMETERS_COLUMN:
	if (value != null) {
	  operation.setParameters(value.toString());
	} else {
	  operation.setParameters((String) null);
	}
	break;
      case VISIBILITY_COLUMN:
	if (value instanceof Visibility) {
	  operation.setVisibility((Visibility) value);
	} else if (value instanceof String) {
	  operation.setVisibility(Visibility.toVisibility((String) value));
	}
	break;
      case CONCURRENCY_COLUMN:
	if (value instanceof Operation.Concurrency) {
	  operation.setConcurrency((Operation.Concurrency) value);
	} else {
	  operation.setConcurrency(null);
	}
	break;
      case ABSTRACT_COLUMN:
	if (value instanceof Boolean) {
	  operation.setAbstract(((Boolean) value).booleanValue());
	}
	break;
      case QUERY_COLUMN:
	if (value instanceof Boolean) {
	  operation.setQuery(((Boolean) value).booleanValue());
	}
	break;
      case STATIC_COLUMN:
	if (value instanceof Boolean) {
	  operation.setStatic(((Boolean) value).booleanValue());
	}
	break;
      case DELETE_COLUMN:
	if (value instanceof Boolean) {
	  deleted = ((Boolean) value).booleanValue();
	}
	break;
      }
    }
  }

  public String getColumnTip(int col) {
    if (col >= 0 && col < columnTips.length) {
      return columnTips[col];
    }
    return null;
  }

  public Class getColumnClass(int col) {
    switch (col) {
    case NAME_COLUMN:
      return String.class;
    case TYPE_COLUMN:
      return String.class;
    case PARAMETERS_COLUMN:
      return String.class;
    case VISIBILITY_COLUMN:
      return String.class;
    case CONCURRENCY_COLUMN:
      return Operation.Concurrency.class;
    case ABSTRACT_COLUMN:
      return Boolean.class;
    case QUERY_COLUMN:
      return Boolean.class;
    case STATIC_COLUMN:
      return Boolean.class;
    case DELETE_COLUMN:
      return Boolean.class;
    default:
      return String.class;
    }
  }

  public Comparator getColumnComparator(int col) {
    if (col >= 0 && col < comparators.length) {
      return comparators[col];
    }
    return null;
  }

  public TableCellEditor getColumnEditor(int col) {
    if (col >= 0 && col < editors.length) {
      return editors[col];
    }
    return null;
  }

  public boolean isColumnEditable(int col) {
    if (col >= 0 && col < columnNames.length) {
      return true;
      // return (col != DELETE_COLUMN);
    }
    return false;
  }

  public TableCellRenderer getColumnRenderer(int col) {
    if (col >= 0 && col < renderers.length) {
      return renderers[col];
    }
    return null;
  }

  public int getColumnWidth(int col) {
    if (col >= 0 && col < columnWidths.length) {
      return columnWidths[col];
    }
    return -1;
  }

  public Operation getOperation() {
    return operation;
  }

  public String getName() {
    if (operation != null) {
      return operation.getName();
    }
    return null;
  }

  public BasicModelElement getModelElement() {
    return operation;
  }

  public boolean isDeleted() {
    return deleted;
  }

  public boolean isEditable() {
    return true;
  }

  protected Operation operation;

  protected boolean deleted;

  static public class FeatureEntryComparator implements Comparator {

    public FeatureEntryComparator(int col) {
      this.col = col;
    }

    public int compare(Object o1, Object o2) {
      if (o1 instanceof UMLOperationEntry && o2 instanceof UMLOperationEntry) {
	UMLOperationEntry e1 = (UMLOperationEntry) o1;
	UMLOperationEntry e2 = (UMLOperationEntry) o2;
	Object v1 = e1.getColumnValue(col);
	Object v2 = e2.getColumnValue(col);
	if (v1 != null && v2 != null) {
	  switch (col) {
	  case VISIBILITY_COLUMN:
	    return ((Visibility) v1).compareTo((Visibility) v2);
	  case CONCURRENCY_COLUMN:
	    return ((Operation.Concurrency) v1)
		.compareTo((Operation.Concurrency) v2);
	  case ABSTRACT_COLUMN:
	  case QUERY_COLUMN:
	  case STATIC_COLUMN:
	    return ((Boolean) v1).compareTo((Boolean) v2);
	  default:
	    return ((String) v1).compareTo((String) v2);
	  }
	}
      }
      return 0;
    }

    protected int col;
  }

}
